/*
 * =====================================================================================
 *
 *       Filename:  message_mysql_adapter.cc
 *
 *    Description:  interface for MySql adapter of IM message.
 *
 *        Version:  1.0
 *        Created:  2013年05月10日 17时20分47秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Wu Yuxin (wyx, Hin)
 *        Company:  www.Qihoo.net
 *
 * =====================================================================================
 */

#include "message_mysql_adapter.h"

#include <boost/format.hpp>
#include <boost/foreach.hpp>
#include "base/logging.h"
#include "database/scoped_connection.h"
#include "../common/common.h"

namespace imserver {

MessageMysqlAdapter::MessageMysqlAdapter(const std::string& databse,
                                         const std::string& addr,
                                         const std::string& user,
                                         const std::string& pwd) : conn_pool_(databse.c_str(), addr.c_str(), user.c_str(), pwd.c_str()) {
  LOG_INFO("MessageMysqlAdapter constructor.");
}

int MessageMysqlAdapter::InsertImMessage(const ImMessage &msg) {
  LOG_INFO("[MessageMysqlAdapter::InsertImMessage] begin.sender-" << msg.sender << " receiver-" << msg.receiver << " body-" << msg.body);
  mysqlpp::ScopedConnection scoped_conn(conn_pool_);
  if (!scoped_conn) {
    LOG_ERROR("insert message error.(DB connect error.)");
    return -1;
  }

  mysqlpp::Query query(scoped_conn->query());
  // INSERT INTO T(...) VALUES (...)
  // body is string, use quote to manip.
  query
    << boost::str(boost::format("INSERT INTO message_history(id,sender,receiver,created_at,flags,body) VALUES (%1%,%2%,%3%,FROM_UNIXTIME(%4%),%5%,")
        % msg.seq_id % msg.sender % msg.receiver % msg.timestamp % msg.flags)
    << mysqlpp::quote << msg.body << ")"
    ;

  try {
    query.exec();
  } catch (mysqlpp::Exception &e) {
    LOG_ERROR(query.str() << " exec ERROR.(" << e.what() << ")");
    return -1;
  }

  return 0;
}

int MessageMysqlAdapter::DeleteImMessage(const int64_t sender, const int64_t receiver, const int64_t seq_id) {
  LOG_INFO("[MessageMysqlAdapter::DeleteImMessage] begin.seq_id-" << seq_id << " sender-" << sender << " receiver-" << receiver);
/*  mysqlpp::ScopedConnection scoped_conn(conn_pool_);
  if (!scoped_conn) {
    LOG_ERROR("delete message error.(DB connect error.)");
    return -1;
  }

  mysqlpp::Query query(scoped_conn->query());

  if (seq_id > 0) {
    query << boost::str(boost::format("UPDATE message_history SET flags=flags&%1% WHERE seq_id=%2%") % 0x2 % seq_id);
  } else {
    query << boost::str(boost::format("UPDATE message_history SET flags=flags&%1% WHERE sender=%2% AND receiver=%3%") % 0x2 % sender % receiver);
  }

  try {
    query.exec();
  } catch ( mysqlpp::Exception& e) {
    LOG_ERROR(query.str() << " exec ERROR.(" << e.what() << ")");
    return -1;
  }
*/
  return 0;
}

int MessageMysqlAdapter::UpdatereadFlagByID(const std::vector<int64_t> & seq_ids, const int64_t uid) {
  LOG_INFO("[MessageMysqlAdapter::UpdatereadFlagByID] begin.receiver-" << uid);
  mysqlpp::ScopedConnection scoped_conn(conn_pool_);
  if (!scoped_conn) {
    LOG_ERROR("update message error.(DB connect error.)");
    return -1;
  }

  mysqlpp::Query query(scoped_conn->query());
  std::string str = boost::str(boost::format("INSERT INTO message_history (id) VALUES "));
  BOOST_FOREACH(const int64_t id, seq_ids) {
    str.append(boost::str(boost::format("(%1%),") % id));
  }
  str = str.substr(0, str.size() - 1);
  str.append(boost::str(boost::format(" ON DUPLICATE KEY UPDATE flags=flags|%1%") % (MSG_FLAG_READ)));
  query << str.c_str();

  LOG_INFO(str);
  try {
    query.exec();
  } catch (mysqlpp::Exception& e) {
    LOG_ERROR(query.str() << " exec ERROR.(" << e.what() << ")");
    return -1;
  }

  return 0;
}

int MessageMysqlAdapter::SelectUnreadMessages(ImMessageList& msg_list, const int64_t receiver, const int32_t offset, const int32_t count) {
  LOG_INFO("[MessageMysqlAdapter::SelectUnreadMessages] begin.receiver-" << receiver << " offset-" << offset);
 /* std::string str = boost::str(boost::format(
        "SELECT id,sender,receiver,UNIX_TIMESTAMP(created_at) AS created_at,flags,body "
        "FROM message_history WHERE (receiver=%1% OR sender=%1%) AND flags&%2%<>%2% ORDER BY id DESC LIMIT %3%, %4%") % receiver % MSG_FLAG_READ % offset % count);
  return __getImMessages(msg_list, str.c_str());
  */return 0;
}

int MessageMysqlAdapter::SelectReadMessages(ImMessageList& msg_list, const int64_t sender, const int64_t receiver, const int32_t offset, const int32_t count) {
  LOG_INFO("[MessageMysqlAdapter::GetReadImMessages] begin.receiver-"<< receiver << " offset-" << offset);
  std::string str = boost::str(boost::format(
        "SELECT id,sender,receiver,UNIX_TIMESTAMP(created_at) AS created_at,flags,body "
        "FROM message_history WHERE (sender=%1% AND receiver=%2%) OR (sender=%2% AND receiver=%1%)"
        " ORDER BY id DESC LIMIT %3%, %4%") % sender % receiver % offset % count);
  return __getImMessages(msg_list, str.c_str());
}

int MessageMysqlAdapter::__getImMessages(ImMessageList& list, const char *command) {
  mysqlpp::ScopedConnection scoped_conn(conn_pool_);
  if (!scoped_conn || NULL == command) {
    LOG_ERROR("get message error.(DB connect error.)");
    return -1;
  }

  mysqlpp::Query query(scoped_conn->query());
  query << command;

  try {
    mysqlpp::UseQueryResult ret = query.use();
    if (ret) {
      while (mysqlpp::Row row = ret.fetch_row()) {
        list.push_back(ImMessage());
        ImMessage& msg = list.back();
        msg.__set_seq_id(row["id"]);
        msg.__set_sender(row["sender"]);
        msg.__set_receiver(row["receiver"]);
        msg.__set_timestamp(row["created_at"]);
        msg.__set_flags(row["flags"]);
        msg.__set_body(row["body"].c_str());
      }
    }
  } catch (mysqlpp::Exception& e) {
    LOG_ERROR(query.str() << " exec ERROR.(" << e.what() << ")");
    return -1;
  }

  return 0;
}

}
